/*
 * By: Werner Schuster (murphee)
 * 
 * Copyright (c) 2005-2006 Werner Schuster (murphee)
 * 
 * This file is part of the EclipseShell project. EclipseShell is subject 
 * to the Eclipse Public License (EPL) available at
 * http://www.eclipse.org/org/documents/epl-v10.php
 * or in the file /epl-v10.html in the source for other info
 * see the /eclipseshell.license file
 */
package net.sf.eclipseshell.editors;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import net.sf.eclipseshell.EclipseShellPlugin;
import net.sf.eclipseshell.extensions.DefaultJavaEnvironment;
import net.sf.eclipseshell.extensions.ExecutionEnvironmentLaunchManager;
import net.sf.eclipseshell.extensions.IExecutionEnvironment;
import net.sf.eclipseshell.extensions.IExecutionEnvironmentProvider;
import net.sf.eclipseshell.extensions.IJavaRuntimeHandler;
import net.sf.eclipseshell.internal.actions.LaunchNewShell;
import net.sf.eclipseshell.internal.actions.LaunchNewShell.ModeFileEditorInput;
import net.sf.eclipseshell.internal.actions.LaunchNewShell.ShellEditorInput;
import net.sf.eclipseshell.internal.extensions.ExecutionProviderManager;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.jface.text.presentation.IPresentationDamager;
import org.eclipse.jface.text.presentation.IPresentationRepairer;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.projection.ProjectionDocument;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.AnnotationPainter.IDrawingStrategy;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.jface.text.source.projection.ProjectionSupport;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;


// TODO: enhancement: add attach/detach functionality for editor, which will allows
// to hook up an editor with an instance of a ExecutionEnvironment. Ie. this could
// allow to start some execution in the background and only afterwards hook up to it.
public class InterpreterEditor extends TextEditor {

	/**
	 * Customize the projection annotation behaviour and look
	 * @author murphee
	 *
	 */
	public class  NonCollapseProjectionAnnotation extends ProjectionAnnotation {
		// HACK: this stops the regions from being collapsible, but keeps the
		// range indication 
		public boolean isCollapsed() {
			return false;
		}
		// TODO: override the drawing behaviour to show faint lines between regions 
	}

	protected void editorContextMenuAboutToShow(IMenuManager menu) {
		super.editorContextMenuAboutToShow(menu);
		addAction(menu, ITextEditorActionConstants.GROUP_REST, DISCONNECT_ACTION_ID);
		
		addAction(menu, ITextEditorActionConstants.GROUP_REST, EVALUATE_SELECTION_ACTION_ID);
		addAction(menu, ITextEditorActionConstants.GROUP_REST, CREATE_AND_OR_EVALUATE_REGION_ACTION_ID);

		
//		addAction(menu, ITextEditorActionConstants.GROUP_REST, CONNECT_ACTION_ID);
	

	}

	public class InterpreterContentProcessor implements IContentAssistProcessor{
		private IContentAssistProcessor processor_;

		public void setContentAssistProcessor(IContentAssistProcessor proc) {
			processor_ = proc;
		}
		
		public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
			ICompletionProposal[] retValue = null;
			if(processor_ != null){
				retValue = processor_.computeCompletionProposals(viewer, offset);
			}
			return retValue;
		}

		// TODO: delegate these
		public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
			// TODO Auto-generated method stub
			return null;
		}

		public char[] getCompletionProposalAutoActivationCharacters() {
			char [] retValue = null;
			if(processor_ != null){
				retValue = processor_.getCompletionProposalAutoActivationCharacters();
			}
			return retValue;
		}

		public char[] getContextInformationAutoActivationCharacters() {
			// TODO Auto-generated method stub
			return null;
		}

		public String getErrorMessage() {
			// TODO Auto-generated method stub
			return null;
		}

		public IContextInformationValidator getContextInformationValidator() {
			// TODO Auto-generated method stub
			return null;
		}

	}


//	private static final String EVALUATE_ACTION_PREFIX = "editor.actions.evaluate";
	private static final String EVALUATE_SELECTION_ACTION_ID = "org.beanshell.eclipse.plugin.actions";
	private static final String CREATE_AND_OR_EVALUATE_REGION_ACTION_ID = "org.beanshell.eclipse.plugin.actions.create_and_or_evaluate_region";
	public static final String REGION_POSITION_TYPE = "net.sf.eclipseshell.editors.region_position_type";
	protected static final String REGION_DELIMITER_TYPE = "net.sf.eclipseshell.editors.region_delimiter_type";

	private static final String AUTOCOMPLETE_ACTION_ID = "org.beanshell.eclipse.plugin.actions.autocomplete_action_id";
	private static final String DISCONNECT_ACTION_ID = "disconnect.from.editor.action";
	private static final String CONNECT_ACTION_ID = "connect.to.environment.action";


	private ColorManager colorManager;

	private IExecutionEnvironment interpreter_;
	MessageConsoleStream msgStream_;
	PrintStream msgStreamWrapper_;
	private ProjectionSupport projectionSupport_;
	private ProjectionAnnotationModel annotationModel_;
	
	
	protected void handleCursorPositionChanged() {
		
		// TODO Auto-generated method stub
		super.handleCursorPositionChanged();
		
	}

	
	
	// Folding support
	public void createPartControl(Composite parent)
	{
	    super.createPartControl(parent);
	    ProjectionViewer viewer =(ProjectionViewer)getSourceViewer();
	   
//	    viewer.getDocument().getP

	    
	    projectionSupport_ = new ProjectionSupport(viewer,getAnnotationAccess(),getSharedColors());
	    projectionSupport_.install();
	    
	    projectionSupport_.setAnnotationPainterDrawingStrategy(new IDrawingStrategy(){
	    	public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) {
	    		if (gc != null) {
	    			
	    			Point left= textWidget.getLocationAtOffset(offset);
	    			int x1= left.x;
//	    			int y1= left.y;
	    			
	    			gc.setForeground(colorManager.getColor(new RGB(240,240,240)));
	    			int verticalOffset = textWidget.getLineHeight()/2;
	    			gc.drawLine(x1, left.y + verticalOffset , textWidget.getBounds().width, left.y + verticalOffset );
//	    			gc.drawLine(x1, left.y + 3 , textWidget.getBounds().width, left.y + 2);
	    			
	    		} else {
	    			textWidget.redrawRange(offset, length, true);
	    		}			
	    	}
	    	
	    });
	    
	    //turn projection mode on
	    viewer.doOperation(ProjectionViewer.TOGGLE);

	    annotationModel_ = viewer.getProjectionAnnotationModel();
	    
//	    getDocumentProvider().getAnnotationModel()
	    
	    

	    

	}
	protected ISourceViewer createSourceViewer(Composite parent,
			IVerticalRuler ruler, int styles)
	{
		ISourceViewer viewer = new ProjectionViewer(parent, ruler,
				getOverviewRuler(), isOverviewRulerVisible(), styles);
		
		// ensure decoration support has been created and configured.
		getSourceViewerDecorationSupport(viewer);
		
		return viewer;
	}
	
	private Annotation[] oldAnnotations;
//	public void updateFoldingStructure(Position[] positions, Position[] delimiterPositions)
	public void updateFoldingStructure(Position[] positions)
	{
	   Annotation[] annotations = new Annotation[positions.length];

	   //this will hold the new annotations along
	   //with their corresponding positions
	   HashMap newAnnotations = new HashMap();
	   
	   // NOTE: currPost is used for the two following loops because it walks over the annotations array
	   // but the twoo 
	   int currPos;
	   for(currPos = 0; currPos < positions.length;currPos++)
	   {
	      ProjectionAnnotation annotation = new NonCollapseProjectionAnnotation();
	      annotation.setRangeIndication(true);
	      // NOTE: added to get rid of folding
	      annotation.markExpanded();

	      newAnnotations.put(annotation, positions[currPos]);
	      annotations[currPos] = annotation;
	   }
//	   // annotate the delimiter regions BUT: hide the range indicator and collapse them so they remain hidden
//	   for(int i = 0; i < delimiterPositions.length;i++, currPos++)
//	   {
//	      ProjectionAnnotation annotation = new InterpreterProjectionAnnotation();
//	      annotation.setRangeIndication(false);
//	      newAnnotations.put(annotation, delimiterPositions[i]);
//	      annotation.markCollapsed();	      
//	      annotation.setText("FooBAR");
//	      annotations[currPos] = annotation;
//	   }

	   
	   // TODO: CRITICAL: add the annotation Model back again! This is just for testing
	   if(annotationModel_ != null){
		   annotationModel_.modifyAnnotations(oldAnnotations, newAnnotations,null);
	   }
	   
	   oldAnnotations = annotations;
	   
	   

	}
	// end Folding support

	
	/**
	 * Needed for hiding the Annotation open/close button in the Vertical ruler.
	 * This is achieved by simply not doing anything in the paint method.
	 */
	public class InterpreterProjectionAnnotation extends ProjectionAnnotation {
		public InterpreterProjectionAnnotation(){
			super();
		}
		public void paint(GC gc, Canvas canvas, Rectangle rectangle) {
			// TODO Auto-generated method stub
//			super.paint(gc, canvas, rectangle);
		}
	}

	
	
	
	
	public InterpreterEditor() {
		super();
		colorManager = new ColorManager();
		setSourceViewerConfiguration(new BeanshellSourceviewerConfiguration(colorManager));
		setDocumentProvider(new BeanshellDocumentProvider());
		
	}

	private IExecutionEnvironment createInterpreter() {
		// TODO: IMPORTANT: find out the files type or extension!!!
		IEditorInput inp = getEditorInput();
		
		if(inp instanceof LaunchNewShell.ShellEditorInput){
			LaunchNewShell.ShellEditorInput shellInput = (ShellEditorInput) inp; 
			IExecutionEnvironmentProvider prov = ExecutionProviderManager.getProvider( ((LaunchNewShell.ShellEditorInput)inp).getExtensionName().trim() );
			return ExecutionEnvironmentLaunchManager.launch(prov, shellInput.getMode(), msgStreamWrapper_, shellInput.getResource());
 
		} else if (inp instanceof IFileEditorInput) {
			IFileEditorInput fileInput = (IFileEditorInput) inp;
			IFile file = fileInput.getFile();
			int lastDot = file.getName().lastIndexOf('.');
			String extension = file.getName().substring(lastDot+1, file.getName().length());
			String mode = null;
			if (inp instanceof ModeFileEditorInput) {
				ModeFileEditorInput modeInp = (ModeFileEditorInput) inp;
				mode = modeInp.getMode();
			}
			IExecutionEnvironmentProvider prov = ExecutionProviderManager.getProvider(extension.trim());
			return ExecutionEnvironmentLaunchManager.launch(prov, mode, msgStreamWrapper_, file);
		} else {
			return null;
		}
	}
	
	public void dispose() {
		colorManager.dispose();
		if(interpreter_ != null){
			ExecutionEnvironmentLaunchManager.shutdown(interpreter_);
		}
		super.dispose();
	}
	
	ProjectionDocument projDoc_;
	private ContentAssistant interpreterContentAssistant;
	private InterpreterContentProcessor interpreterContentAssistProcessor;
	private DefaultJavaEnvironment javaEnvironment_;
	
    protected void createActions() {
    	super.createActions();
    	
    	// setup auto complete action
    	setActionActivationCode(AUTOCOMPLETE_ACTION_ID, ' ', -1, SWT.CTRL);
    	setAction(AUTOCOMPLETE_ACTION_ID, new Action() {	
    		public void run() {
    			interpreterContentAssistant.showPossibleCompletions();
    		}
    	});
        interpreterContentAssistant = new ContentAssistant();
        interpreterContentAssistant.setInformationControlCreator(new IInformationControlCreator(){
			public IInformationControl createInformationControl(Shell parent) {
				return new DefaultInformationControl(parent);
			}
        	
        });
        interpreterContentAssistProcessor = new InterpreterContentProcessor();
        interpreterContentAssistant.setContentAssistProcessor(interpreterContentAssistProcessor,
                        IDocument.DEFAULT_CONTENT_TYPE);
        interpreterContentAssistant.install(getSourceViewer());

    	
    	
    	// setup position categories
		IDocument handlerDoc =  getDocumentProvider().getDocument(getEditorInput());
		handlerDoc.addPositionCategory(REGION_DELIMITER_TYPE);
		handlerDoc.addPositionCategory(REGION_POSITION_TYPE);
		
		
		
//		
    	setAction(EVALUATE_SELECTION_ACTION_ID, new Action() {	
    		public String getText() {
    			return "Evaluate Selection";
    		}
    		public int getAccelerator() {
      			return SWT.CTRL|'\r';
    		}
    		public  void run(){
    			try {
    				ensureInterpreterIsSetup();
    				IDocument doc = getDocumentProvider().getDocument(getEditorInput());
    				Position region;

    		    	region = getSelectedRegion();
    		    	    		    	
    		    	evaluateRegion(doc, region);
    			} catch (BadLocationException e2) {
    				EclipseShellPlugin.getDefault().log(Status.WARNING, e2.getLocalizedMessage(), e2);
    			}
    		}
		
			

    	});

    	setActionActivationCode(EVALUATE_SELECTION_ACTION_ID, '\r', -1, SWT.CTRL);
    	

    	// setup action for handling region creation and/or evaluation
      	setAction(CREATE_AND_OR_EVALUATE_REGION_ACTION_ID, new Action() {	
      		public String getText() {
      			return "Evaluate Region";
      		}
      		public int getAccelerator() {
      			return SWT.CTRL|SWT.ALT|'\r';
      		}
			public  void run(){
      			try {
      				ensureInterpreterIsSetup();
      				IDocument doc = getDocumentProvider().getDocument(getEditorInput());
      				Position region = getEvaluationRegion(doc);
      				if(region == null){
      					region = addEvaluationRegion(doc);
      					getSelectionProvider().setSelection(new TextSelection(doc, doc.getLength(),0));
      				}
  					try {
						updateFoldingStructure(doc.getPositions(REGION_POSITION_TYPE));
					} catch (BadPositionCategoryException e) {
						EclipseShellPlugin.getDefault().log(Status.WARNING, e.getLocalizedMessage(), e);
					}
  					
      				evaluateRegion(doc, region);
      			} catch (BadLocationException e2) {
      				EclipseShellPlugin.getDefault().log(Status.WARNING, e2.getLocalizedMessage(), e2);
      			}
      		}
		
    	});

    	setActionActivationCode(CREATE_AND_OR_EVALUATE_REGION_ACTION_ID, '\r', -1, SWT.CTRL|SWT.ALT);
    	
    	
    // setup disconnect action
    	setAction(DISCONNECT_ACTION_ID, new Action() {	
    		public  void run(){
    			interpreter_ = null;
    		}		
    		public String getText() {
    			return "Disconnect Editor"; 
    		}


    	});
    	
//    	setAction(CONNECT_ACTION_ID, new ConnectAction());
	
    	
    	

//    	setActionActivationCode(EVALUATE_SELECTION_ACTION_ID, '\r', -1, SWT.CTRL);
    	
    }

    public class ConnectAction extends Action implements IMenuCreator {
    	public ConnectAction(){
    		super("Connect To...", Action.AS_DROP_DOWN_MENU);
    		setMenuCreator(this);
    	}
    	
    	
    	public  void run(){
    		Set allActiveExecutionEnvironments = ExecutionEnvironmentLaunchManager.getAllActiveExecutionEnvironments();
    		for (Iterator iter = allActiveExecutionEnvironments.iterator(); iter
    		.hasNext();) {
    			IExecutionEnvironment env = (IExecutionEnvironment) iter.next();
    			interpreter_ = env;
    			// TODO: HACK!!!! Do the drop down menu bit here!
    			break;
    		}
    	}		
//    	public String getText() {
//    		return "Connect Editor to"; 
//    	}
//    	
    	public void dispose() {
    		// TODO Auto-generated method stub
    		
    	}
    	
    	public Menu getMenu(Control parent) {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	
    	public Menu getMenu(Menu parent) {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	
    }

    
    
    private Position getSelectedRegion() {
		ISelection sel = getSelectionProvider().getSelection();
		if (sel instanceof TextSelection) {
			TextSelection textSelection = (TextSelection) sel;
			return new Position(textSelection.getOffset(), textSelection.getLength() );				
		}
		return null;
	}
    
    private void evaluateRegion(IDocument doc, Position region) throws BadLocationException {
		if(region !=  null){
			String code = null;
//			System.out.println("Code: " + code + ", "+region.getLength());
			code = doc.get(region.getOffset(), region.getLength());
//			System.out.println("Code: " + code + ", "+region);
//	    		msgStreamWrapper_.println("[CODE:"+code+"]");
			
			executeInBackground(interpreter_, code);
			
			

		}
	}
    
    private void executeInBackground(IExecutionEnvironment interpreter_2, String code) {    	
    	EvaluateJob job = new EvaluateJob("Execute Code", interpreter_2, code);
    	job.schedule();
    }
    
	class EvaluateJob extends Job {

		private IExecutionEnvironment execEnvironment_;
		private String code_;

		public EvaluateJob(String name, IExecutionEnvironment interp, String code) {
			super(name);
			execEnvironment_ = interp;
			code_ = code;
		}

		protected IStatus run(IProgressMonitor monitor) {
			try{
				if(execEnvironment_ != null){
					execEnvironment_.execute(code_);
				} else {
					EclipseShellPlugin.getDefault().log(IStatus.ERROR, "Interpreter was not instantiated.", null);
				}
			}finally{
				monitor.done();
			}
			return Status.OK_STATUS;
		}
    	
    }
    
    
    private void ensureInterpreterIsSetup() {
		if(msgStream_ == null){

		    // TODO: add message stream to ExecutionManager! 
		    msgStream_ = createMessageStream();

		    msgStreamWrapper_ = new PrintStream(msgStream_);

			if(interpreter_ == null){		    	
		    	interpreter_ = createInterpreter();
		    }
		    
			IProject proj = null;
			// TODO: check if something like the Adapter system would be better to handle this!
			IEditorInput editorInput = getEditorInput();
			if (editorInput instanceof IFileEditorInput) {
				IFileEditorInput fileInput = (IFileEditorInput) editorInput;
				proj = fileInput.getFile().getProject();
			}
			if(editorInput instanceof LaunchNewShell.ShellEditorInput){
				LaunchNewShell.ShellEditorInput shellInput = (ShellEditorInput) editorInput;
				IResource resource = shellInput.getResource();
				if(resource != null){
					proj = resource.getProject();
				}
			}
			// if this is a Java Environment, then set it up with the IJavaEnvironment
			if (interpreter_ instanceof IJavaRuntimeHandler) {
				IJavaRuntimeHandler currHandler = (IJavaRuntimeHandler) interpreter_;
				javaEnvironment_ = new DefaultJavaEnvironment(proj);
				currHandler.setJavaEnvironment(javaEnvironment_);
			}
			// setup IExecutionEnvironment specific Content Assist and TextHover and syntax highlighting
			interpreterContentAssistProcessor.setContentAssistProcessor(interpreter_.getContentAssistProcessor(proj));
			InterpreterTextHover hover = (InterpreterTextHover)getSourceViewerConfiguration().getTextHover(getSourceViewer(), null);
			hover.setTextHover(interpreter_.getTextHover(proj));
			Object[] damagerAndRepairer  = interpreter_.getDamagerAndRepairer();
			if(damagerAndRepairer != null &&  damagerAndRepairer.length == 2){
				PresentationReconciler reconciler = (PresentationReconciler)getSourceViewerConfiguration().getPresentationReconciler(getSourceViewer());
				IPresentationDamager damager = (IPresentationDamager)damagerAndRepairer[0];
				IPresentationRepairer repairer = (IPresentationRepairer)damagerAndRepairer[0];
				IDocument doc = getDocumentProvider().getDocument(getEditorInput());
				damager.setDocument(doc);
				repairer.setDocument(doc);
				reconciler.setDamager(damager, IDocument.DEFAULT_CONTENT_TYPE);
				reconciler.setRepairer(repairer,IDocument.DEFAULT_CONTENT_TYPE);
			}
			
			
//		    interpreter_.setOut(msgStreamWrapper_);
//		    interpreter_.setErr(msgStreamWrapper_);
		}
	}
	List regionList_ = new ArrayList();

    
    /**
     * Gets the region for this evaluation; if a region for the current cursor position doesn not 
     * exist yet, it will be created.
     * @param doc the IDocument to work on 
     * @return an IRegion object describing the region OR null if no matching region could be found or created
     */
    protected Position getEvaluationRegion(IDocument doc) {

    	ISelection sel = getSelectionProvider().getSelection();
		if (sel instanceof TextSelection) {
			TextSelection textSelection = (TextSelection) sel;
			// TODO: selection evaluation is not supported at the moment, so 
			// this just looks for the current selections start to figure out the region.
			int start = textSelection.getOffset();

			try {
				Position[] positions = doc.getPositions(REGION_POSITION_TYPE);
				for (int i = 0; i < positions.length; i++) {
					if(positions[i].includes(start)){
						return positions[i];
					}
				}
				return null;
			} catch (BadPositionCategoryException e) {
				EclipseShellPlugin.getDefault().log(Status.WARNING, e.getLocalizedMessage(), e);
			}
			
		}
		return null;
	}
    
    
    private Position addEvaluationRegion(IDocument doc) {
    	Position[] positions;
    	
    	Position newRegion = null;
    	
    	try {
    		positions = trimPositions(doc.getPositions(REGION_POSITION_TYPE), doc.getLength());
    		doc.replace(doc.getLength(), 0, "\n");
    		if(positions.length  < 1){			
    			newRegion = new Position(0, doc.getLength() );
    			doc.addPosition(REGION_POSITION_TYPE, newRegion);
    		} else {
    			// careful: the end of the delimiter points to it's "\n", +1 points to the first char of the new line
    			
    			int delimiterEnd = positions[positions.length-1].offset + positions[positions.length-1].length; 
    			int regionStart = delimiterEnd;
    			
    			if(regionStart == doc.getLength()){
    				// TODO: might be the cause of the problem of too short regions!
    				doc.replace(doc.getLength(), 0, "\n");
    				positions[positions.length-1].setLength(positions[positions.length-1].length -1);
    			}
    			newRegion = new Position(regionStart, doc.getLength() - regionStart);
    			doc.addPosition(REGION_POSITION_TYPE, newRegion);
    		}

    		doc.replace(doc.getLength(), 0, "\n");
    		
    	} catch (BadPositionCategoryException e) {
			EclipseShellPlugin.getDefault().log(Status.WARNING, e.getLocalizedMessage(), e);
    	} catch (BadLocationException e) {
			EclipseShellPlugin.getDefault().log(Status.WARNING, e.getLocalizedMessage(), e);
    	}
    	return newRegion;
    	
    }
	
	/**
	 * Checks for all Positions with length == 0 and deletes them; the returned value consists only of Position objects with length > 0.  
	 * 
	 * @param positions the document positions
	 * @param docLength 
	 * @return the trimmed positions
	 */
	private Position[] trimPositions(Position[] positions, int docLength) {
		List trimmedPositions  = new ArrayList();
		for (int i = 0; i < positions.length; i++) {
			Position currPosition = positions[i];
			if(currPosition.getLength() > 0 && currPosition.getOffset() < docLength){
				trimmedPositions.add(currPosition);
			} else {
				currPosition.delete();
			}
		}
		return (Position[]) trimmedPositions.toArray(new Position[trimmedPositions.size()]);
	}



	private MessageConsoleStream createMessageStream() {
		MessageConsole msgConsole = new MessageConsole(
				"EclipseShell:"+getEditorInput().getName() , null); 
		ConsolePlugin.getDefault().getConsoleManager().addConsoles(
				new IConsole[] { msgConsole });
		ConsolePlugin.getDefault().getConsoleManager().showConsoleView(
				msgConsole);
		MessageConsoleStream msgStream = msgConsole.newMessageStream();
		return msgStream;
	}


	/**
	 * Connects this editor to the given @see IExecutionEnvironment
	 *
	 * @param env 
	 */
	public void connectTo(IExecutionEnvironment env) {
		// TODO: check if there's anything else to update here
		interpreter_ = env;
		
	}

}
